/**
  slice 切片， 本质山和深度赋值有什么区别？
  还有什么更丰富的用途？    
  
  1. 字符串的切片类型定义为 &str
     各种切片语法的含义
	 &s[..]   -- 等同于s
	 &s[n..m] -- 取从n到m-1的部分，其中n>=0
	 &s[..n]  -- 取0到n-1的部分
	 &s[n..]  -- 取从n及其之后的所有
  2. 字符串字面量就是字符串切片
     let s="abc"; 这个s就是 &str
  3. 切片的存在，然rust的代码比较难度读懂，需要足够的时间练习
     切片的值存放在堆还是栈中?
	 对切片的修改是否会修改被引用的原来的值	
	 
	 字符串切片的存在，使得可以随意使用一个字符串变量。
	 
  4. 其它数据类型的切片
     元组切片？
	 数组切片 
  
 */
 
fn main(){
	
	let mut s=String::from("a*b$c&d#e@f-gg-kill");
	let b=fn_s_withref(&s);
	println!("{} 的头四个： {}",s,b);
	let b1=fn_s_withsc(&b[..]);
	println!("{}的第一个字符是{}",b,b1);
	
	
	let c=fn_s1(&s);
	println!("{}",c);
	println!("{}***",s);
	
	//打印字符串字面量的类型
	let gs="good";
	print_type_of(&gs);
	
	// &符号可以用在堆类型前，也可以用在栈类型前，例如那些简单的类型
	let money=99.99;
	print_type_of(&money);
	
    //演示字符切片
	show_string_slice();
	// 演示其它切片
	show_other_slice();
	
	// 演示修改切片对被切对象的影响.
}

/**
  为了保证不错误，必须把参数定义为引用，
  其次为了返回部分值，那么需要使用切片。
  如果不用切片，那么会触发错误：
 */
fn fn_s_withref(s:&String)->&str{	
	&s[0..4]
}

/**
  切片可以作为参数
 */
fn fn_s_withsc(s:&str)->&str{	
	&s[0..1]
}

fn show_string_slice(){
	let name=String::from("ABCDEF GHIJKLMN");
	let s1=&name[0..4];
	let s2=&name[5..10];
	println!("s1={},s2={}",s1,s2);
}

fn show_other_slice(){
	let scores=[1,2,3,4,5];
	let foods=("主食","配菜","汤","配料","饮料","小吃");
	
	//变量命名比较随意
	let first_5_scores=&scores[0..5];
	let first_food=&foods.0;
	
	print_use_for_loop_1(&scores);
	print_use_for_loop_2(&scores);
	print_use_for_loop_3_iter(&scores);
}

//演示for的几种打印方式
fn print_use_for_loop_1(arr:&[u32]){
	println!("---- 使用 最简单的for循环 打印数组元素");
	for i in 0..arr.len() {  
       print!("{}", arr[i].to_string());  
    } 
	println!("\n");
}

fn print_use_for_loop_2(arr:&[u32]){
	println!("---- 使用 for 循环和 & 引用迭代 打印数组元素");
	for &ele in arr {  
       print!("{}", ele);  
    } 
	println!("\n");
}

fn print_use_for_loop_3_iter(arr:&[u32]){
	//注意这个是针对固定数组，如果是可变数组则可以
	//for element in array.into_iter()
	
	println!("---- 使用 for 循环和迭代iter 打印数组元素");	
	for ele in arr.iter() {  
       print!("{}", ele);  
    } 
	println!("\n");
}


/**
  这也是一个正确的函数，应为s来自于外面，不会因为离开范围而消亡,从而引发错误
 */
fn fn_s1(s:&String)->&String{	
	&s
}

// 使用 print_type_of 函数打印变量类型
// rust的语法很让人看不懂
fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}